﻿Imports System.IO
Imports System.Reflection

Public Class StateReader
    Implements IDisposable
    Private _Info As CompilerInfo
    Public ReadOnly Property Info As CompilerInfo
        Get
            Return _Info
        End Get
    End Property
    Public Sub New(Inf As CompilerInfo)
        _Info = Inf
    End Sub
    Public Function ReadState(Rdr As TextReader) As Object
        'Initializing
        For Each p As TypeProvider In Info.TypeProviders.Values
            p.Initialize(Info, Rdr, Nothing)
        Next
        'Deserializing
        ReadState = DeserializeInternal(Rdr)
        'Finalizing
        For Each p As TypeProvider In Info.TypeProviders.Values
            p.Finalize()
        Next
        Info.ClearCache()
    End Function
    Public Function DeserializeInternal(Rdr As TextReader) As Object
        'Checking Type Name
        Dim TypeName = ""
        While Rdr.Peek <> -1
            Dim Ch = Chr(Rdr.Read)
            If TypeProvider.IsValidChar(Ch) Then
                If Ch = Info.ObjectId Then
                    'Getting From Cache
                    Dim Cs = ""
                    While Rdr.Peek <> -1
                        Ch = Chr(Rdr.Peek)
                        If IsUInt(Ch) Then
                            Cs += Ch
                            Rdr.Read()
                        Else
                            Exit While
                        End If
                    End While
                    Return Info.GetCache(CInt(Val(Cs)))
                ElseIf Ch = Info.Null Then
                    'Ret Null
                    Return Nothing
                ElseIf Ch = Info.StartBlock Then
                    'Type Name Got
                    Exit While
                Else
                    TypeName += Ch
                End If
            End If
        End While
        'Getting Type
        Dim Typ As Type = Nothing
        If Info.RealTypeProvider Is Nothing Then
            'Find Type from all loaded Assemblies
            Typ = Type.GetType(TypeName)
            If Typ Is Nothing Then
                Dim Asm = AppDomain.CurrentDomain.GetAssemblies()
                For Each a As Assembly In Asm
                    Typ = a.GetType(TypeName)
                    If Typ IsNot Nothing Then
                        Exit For
                    End If
                Next
            End If
        Else
            'Or Get it from custom type provider
            Typ = Info.RealTypeProvider.Invoke(TypeName)
        End If
        'Type must not be null
        If Typ Is Nothing Then
            Throw New Exception("Given Type Not Found")
        End If
        'Find Provider
        Dim TP = Info.FindProvider(Typ)
        'Provider must not be null
        If TP Is Nothing Then
            Throw New Exception("Unsupported Type")
        End If
        'Getting Object
        Return TP.ReadObject(Typ)
    End Function
    Private Function IsUInt(Str As String) As Boolean
        Dim b As Byte = Nothing
        For Each c As Char In Str
            b = Asc(c)
            If Not (b >= 48 And b <= 57) Then
                Return False
            End If
        Next
        Return True
    End Function
#Region "IDisposable Support"
    Private disposedValue As Boolean
    Protected Overridable Sub Dispose(disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
            End If
            _Info = Nothing
        End If
        Me.disposedValue = True
    End Sub
    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region
End Class